﻿// -----------------------------------------------------------------------
// <copyright file="AtoReplays.cs" company="Microsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace JumpJump.Offline
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.IO;
    using JumpJump.Runtime;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class AtoReplays
    {
        /// <summary>
        /// raw X to my chessboard coordinate X range
        /// </summary>
        private int[,] _rawXToProcessedXRange = new int[18, 2]
        {
            { 0, 0 }, // x=0
            { 5, 5 }, // x=1
            { 5, 6 }, // x=2
            { 5, 7 }, // x=3
            { 5, 8 }, // x=4
            { 1, 13 }, // x=5
            { 2, 13 }, // x=6
            { 3, 13 }, // x=7
            { 4, 13 }, // x=8
            { 5, 13 }, // x=9
            { 5, 14 }, // x=10
            { 5, 15 }, // x=11
            { 5, 16 }, // x=12
            { 5, 17 }, // x=13
            { 10, 13 }, // x=14
            { 11, 13 }, // x=15
            { 12, 13 }, // x=16
            { 13, 13 }, // x=17
        };

        /// <summary>
        /// raw X to my chessboard coordinate Y range
        /// </summary>
        private int[,] _rawXToProcessedYRange = new int[18, 2]
        {
            { 0, 0 }, // x=0
            { 13, 13 }, // x=1
            { 12, 13 }, // x=2
            { 11, 13 }, // x=3
            { 10, 13 }, // x=4
            { 5, 17 }, // x=5
            { 5, 16 }, // x=6
            { 5, 15 }, // x=7
            { 5, 14 }, // x=8
            { 5, 13 }, // x=9
            { 4, 13 }, // x=10
            { 3, 13 }, // x=11
            { 2, 13 }, // x=12
            { 1, 13 }, // x=13
            { 5, 8 }, // x=14
            { 5, 7 }, // x=15
            { 5, 6 }, // x=16
            { 5, 5 }, // x=17
        };

        /// <summary>
        /// rule to match move informations
        /// </summary>
        private Regex _movementPattern = new Regex("<ROW RowState=\"\\d\"[^<]+Rem=[^<]+/>");

        /// <summary>
        /// rule to match from coordinate
        /// </summary>
        private Regex _getFromPattern = new Regex("FX=\"(?<FromX>-?\\d)\".+FY=\"(?<FromY>-?\\d)\"");

        /// <summary>
        /// rule to match target coordinate
        /// </summary>
        private Regex _getToPattern = new Regex("ToX=\"(?<ToX>-?\\d)\".+ToY=\"(?<ToY>-?\\d)\"");

        /// <summary>
        /// raw action list
        /// </summary>
        private List<ManualAction> _rawActionList = new List<ManualAction>();

        /// <summary>
        /// converted action list
        /// </summary>
        private List<ManualAction> _processedActionList = new List<ManualAction>();

        /// <summary>
        /// generated manual list
        /// </summary>
        private List<ChessManual> _manualList = new List<ChessManual>();

        /// <summary>
        /// load from file path and generate whole movement list
        /// </summary>
        /// <param name="filePath">replays file path</param>
        /// <param name="logPath">log file path</param>
        public void Load(string filePath, string logPath)
        {
            using (StreamReader sr = new StreamReader(filePath, Encoding.UTF8))
            using (StreamWriter sw = new StreamWriter(logPath, true, Encoding.Unicode))
            {
                string allString = sr.ReadToEnd();

                // match raw movement
                MatchCollection movementMatches = _movementPattern.Matches(allString);

                foreach (Match oneMove in movementMatches)
                {
                    string moveInfo = oneMove.Value;

                    // get from coordinate
                    Match fromInfo = _getFromPattern.Match(moveInfo);
                    int fromX = int.Parse(fromInfo.Groups["FromX"].Value);
                    int fromY = int.Parse(fromInfo.Groups["FromY"].Value);

                    // get to coordinate
                    Match toInfo = _getToPattern.Match(moveInfo);
                    int toX = int.Parse(toInfo.Groups["ToX"].Value);
                    int toY = int.Parse(toInfo.Groups["ToY"].Value);

                    ManualAction oneAction = new ManualAction(fromX, fromY, toX, toY);
                    _rawActionList.Add(oneAction);
                }

                foreach (ManualAction action in _rawActionList)
                {
                    sw.WriteLine(action.ToString());
                }
            }
        }

        /// <summary>
        /// convert raw action list
        /// </summary>
        /// <param name="logPath">log file path</param>
        public void GetConvertedActionList(string logPath)
        {
            using (StreamWriter sw = new StreamWriter(logPath, true, Encoding.Unicode))
            {
                foreach (ManualAction rawAction in _rawActionList)
                {
                    ManualAction processedAction = Convert(rawAction);
                    _processedActionList.Add(processedAction);
                    sw.WriteLine(processedAction.ToString());
                }
            }
        }

        /// <summary>
        /// generated the manual list from this replay
        /// start chessboard is initial board, means all pieces are in default position
        /// </summary>
        /// <param name="logPath">log file path</param>
        public void GenerateChessManual(string logPath)
        {
            int[,] currentBoard = Chessboard.InitialBoard();

            foreach (ManualAction oneStep in _processedActionList)
            {
                List<ManualAction> actionList = new List<ManualAction>();
                actionList.Add(oneStep);
                ChessManual oneManual = new ChessManual(currentBoard, actionList);
                _manualList.Add(oneManual);

                currentBoard[oneStep.ToX, oneStep.ToY] = currentBoard[oneStep.FromX, oneStep.FromY];
                currentBoard[oneStep.FromX, oneStep.FromY] = Chessboard.EmptyPosition;
            }

            using (StreamWriter sw = new StreamWriter(logPath, true, Encoding.Unicode))
            {
                foreach (ChessManual cm in _manualList)
                {
                    sw.WriteLine(cm.ToString());
                }
            }
        }

        /// <summary>
        /// save manual list to dat file
        /// </summary>
        /// <param name="path">output file path</param>
        public void SaveChessManual(string path)
        {
            ChessManual.Serialized(path, _manualList);
        }

        /// <summary>
        /// convert one raw movement to coordinate base one my own
        /// </summary>
        /// <param name="rawAction">raw coordinate</param>
        /// <returns>converted coordinate</returns>
        private ManualAction Convert(ManualAction rawAction)
        {
            int processedFromY = rawAction.FromY + 9;
            int processedToY = rawAction.ToY + 9;

            int processedFromX =
                _rawXToProcessedXRange[rawAction.FromX + 9, 0]
                + processedFromY
                - _rawXToProcessedYRange[rawAction.FromX + 9, 0];

            int processedToX =
                _rawXToProcessedXRange[rawAction.ToX + 9, 0]
                + processedToY
                - _rawXToProcessedYRange[rawAction.ToX + 9, 0];

            ManualAction convertedAction = new ManualAction(
                processedFromX,
                processedFromY,
                processedToX,
                processedToY);

            return convertedAction;
        }
    }
}
